package ar.edu.caece.pl.asem.codegenerator;

import java.util.ArrayList;
import java.util.HashMap;

import ar.edu.caece.pl.asem.model.impl.Ambiente;
import ar.edu.caece.pl.asem.model.impl.SymbolTable;
import ar.edu.caece.pl.asem.model.impl.treeelements.AbstractElement;
import ar.edu.caece.pl.asem.model.tree.Tree;
import ar.edu.caece.pl.asem.model.tree.TreeNode;
import ar.edu.caece.pl.asem.temp.TemporalGenerator;

public class CodeGenerator {

	private static CodeGenerator instance = null;

	public static synchronized CodeGenerator getInstance() {
		if (instance == null) {
			instance = new CodeGenerator();
		}
		return instance;
	}

	private Tree semanticTree;
	private Assembler assembler = new Assembler();

	public CodeGenerator() {

	}

	public String generateCode() {
		StringBuffer code = new StringBuffer();
		code.append(assembler.start());
		// Nombres de funcion/procedimiento con sus respectivos parametros
		// Constantes y Variables globales.
		HashMap<String, AbstractElement> simbolos = new HashMap<String, AbstractElement>();
		SymbolTable.getInstance();
		Ambiente ambiente = SymbolTable.getInstance().getAmbiente("AMBIENTE_GLOBAL");
			simbolos.putAll(ambiente.getVariables());
			simbolos.putAll(ambiente.getConstantes());
			simbolos.putAll(ambiente.getParametrosMap());
			simbolos.putAll(ambiente.getArreglos());
		
		semanticTree.generarFunciones(semanticTree.getRoot(),simbolos);

		String globalMemory = assembler.generateGlobalMemory(simbolos);
		code.append(globalMemory);
		String programa = start();
		String temporalCode = TemporalGenerator.getInstance()
				.generateTemporalAssemblerCode();
		code.append(temporalCode);
		code.append(PreDefinedFunctions.sb.toString());

		// code.append(tablaTemporal.getCodigoTablaTemporal());
		// code.append("Comienzo: \n");
		code.append(programa);
		System.out.println(code);

		return code.toString();
	}

	private String start() {
		StringBuilder sb = new StringBuilder();
		TreeNode<AbstractElement> root = (TreeNode<AbstractElement>) semanticTree
				.getRoot().getChildren().get(1);

		semanticTree.fillData(root, new ArrayList<AbstractElement>());

		AbstractElement rootElement = root.getData();

		rootElement.generateASMCode();
		
		sb.append(rootElement.code);

		return sb.toString();
	}

	public void setTree(Tree semanticTree) {
		this.semanticTree = semanticTree;
	}
}
